package engine.graphics.popup;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

import engine.CityAction;
import engine.GameEngine;
import engine.data.Building;
import engine.data.City;
import engine.data.People;
import engine.data.Player;
import engine.data.Resource;
import engine.data.Terrain;
import engine.data.Tile;
import engine.data.Unit;
import engine.data.UnitType;
import engine.data.factories.PeopleFactory;
import engine.data.factories.ResourceFactory;
import engine.graphics.MapCanvasEngine;
import engine.graphics.misc.GraphicsCustomFont;

public final class PopupCity extends TabPopup {

	public static final byte PROD_PANEL = 1;

	public static final byte MAP_PANEL = 2;

	public static final byte INFOS_PANEL = 3;

	private static final int[][][] PRODUCTION_CURSOR = new int[][][] { { { 2, 78 }, { 130, 11 } },
			{ { 2, 89 }, { 130, 11 } }, { { 2, 100 }, { 130, 11 } }, { { 2, 111 }, { 130, 11 } },
			{ { 2, 122 }, { 130, 11 } } };

	private static int[][][] popCursor;

	private static byte[] availSpecPop;

	private static int[][][][] mapCursor;

	private City city;

	private byte vMapIndex = 0;

	private byte hPopIndex = 0;

	private byte hCityMapIndex = 2;

	private byte vCityMapIndex = 2;

	private byte vProductionIndex = 0;

	private Player player;

	public PopupCity(final Player gamePlayer, final City currCity, final byte initPanel) {
		tabCursor = new int[][][] { { { 1, 1 }, { 17, 11 } }, { { 20, 1 }, { 29, 11 } }, { { 50, 1 }, { 19, 11 } },
				{ { 70, 1 }, { 29, 11 } } };
		this.player = gamePlayer;
		this.city = currCity;
		hIndex = initPanel;
	}

	public PopupCity(final Player gamePlayer, final City currCity) {
		this(gamePlayer, currCity, PROD_PANEL);
	}

	public void show(final int screenX, final int screenY) {
		super.show(screenX, screenY, MapCanvasEngine.canvas.graphics);
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		graphics.setColor(128, 128, 128);
		graphics.fillRect(this.x, this.y, width, 15);
		GraphicsCustomFont.drawString(graphics, "[X] Prod. Map Infos", this.x + 2, this.y + 3);
		showHCursor();
		showPanel();
	}

	public void keyPressed(final int key) {
		int action = MapCanvasEngine.canvas.getGameAction(key);
		if (action != 0)
			switch (action) {
				case Canvas.DOWN:
					switch (hIndex) {
						case PROD_PANEL:
							if (hCursorScope) {
								hideHCursor();
								showVCursor(PRODUCTION_CURSOR, vProductionIndex);
							} else if (vProductionIndex % PRODUCTION_CURSOR.length == PRODUCTION_CURSOR.length - 1) {
								hideVCursor(PRODUCTION_CURSOR, vProductionIndex);
								showHCursor();
								vProductionIndex = 0;
							} else
								vProductionIndex = moveVCursor(PRODUCTION_CURSOR, vProductionIndex, (byte) 1);
							break;
						case MAP_PANEL:
							if (this.vMapIndex == 1)
								moveCityMapCursor((byte) 0, (byte) 1);
							else
								moveVMapCursor((byte) 1);
							break;
						default:
							break;
					}
					this.repaint();
					break;
				case Canvas.UP:
					switch (hIndex) {
						case PROD_PANEL:
							if (hCursorScope) {
								hideHCursor();
								vProductionIndex = (byte) (PRODUCTION_CURSOR.length - 1);
								showVCursor(PRODUCTION_CURSOR, vProductionIndex);
							} else if (vProductionIndex % PRODUCTION_CURSOR.length == 0) {
								hideVCursor(PRODUCTION_CURSOR, vProductionIndex);
								showHCursor();
							} else
								vProductionIndex = moveVCursor(PRODUCTION_CURSOR, vProductionIndex, (byte) -1);
							break;
						case MAP_PANEL:
							if (this.vMapIndex == 1)
								moveCityMapCursor((byte) 0, (byte) -1);
							else
								moveVMapCursor((byte) -1);
							this.repaint();
							break;
						default:
							break;
					}
					this.repaint();
					break;
				case Canvas.LEFT:
					if (hIndex == MAP_PANEL) {
						if (this.vMapIndex == 1)
							moveCityMapCursor((byte) -1, (byte) 0);
						else if (this.vMapIndex == 2)
							moveHPopCursor((byte) -1);
						else
							showNextTab((byte) -1);
					} else
						showNextTab((byte) -1);
					this.repaint();
					break;
				case Canvas.RIGHT:
					if (hIndex == MAP_PANEL) {
						if (this.vMapIndex == 1)
							moveCityMapCursor((byte) 1, (byte) 0);
						else if (this.vMapIndex == 2)
							moveHPopCursor((byte) 1);
						else
							showNextTab((byte) 1);
					} else {
						showNextTab((byte) 1);
						showPanel();
					}
					this.repaint();
					break;
				case Canvas.FIRE:
					switch (hIndex) {
						case PROD_PANEL:
							switch (vProductionIndex) {
								case 0:
									PopupManager.showPopupProduction(this.city);
									break;
								case 2:
									PopupManager.showPopupBuildings(this.city);
									break;
								case 3:
									PopupManager.showPopupFortifiedUnits(this.city);
									break;
								case 4:
									PopupManager.showPopupAttachedUnits(this.city);
									break;
								default:
									break;
							}
							break;
						case MAP_PANEL:
							CityAction cityAction = null;
							if (this.vMapIndex == 1)
								cityAction = new CityAction(city, this.hCityMapIndex, this.vCityMapIndex);
							else if (this.vMapIndex == 2)
								cityAction = new CityAction(city, availSpecPop[this.hPopIndex]);
							if (cityAction != null)
								GameEngine.doCityAction(cityAction);
							if (this.vMapIndex == 1)
								refreshCityMap();
							else if (this.vMapIndex == 2)
								refreshCityPeople();
							break;
						case INFOS_PANEL:
							break;
						case CLOSE_PANEL:
							this.hide();
							break;
						default:
							break;
					}
					break;
				default:
					break;
			}
	}

	public void refreshCityMap() {
		drawMap();
		drawPopulation();
		showCityMapCursor();
		this.repaint();
	}

	public void refreshCityPeople() {
		drawMap();
		drawPopulation();
		showHPopCursor();
		this.repaint();
	}

	private void showProductionPanel() {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		graphics.setColor(192, 192, 192);
		graphics.fillRect(this.x + 1, this.y + 15, 133, 104);
		/*
		 * graphics.drawImage(this.unit.getImage(), this.x + 3, this.y + 18,
		 * Graphics.TOP | Graphics.LEFT);
		 */
		if (city.buildingType != null) {
			if (city.buildingType.equals(Building.class)) {
				GraphicsCustomFont.drawString(graphics, Building.getName(city.buildingId), this.x + 5, this.y
						+ MARGIN_PANEL_HEIGHT);
			}
			if (city.buildingType.equals(Unit.class)) {
				GraphicsCustomFont.drawString(graphics, UnitType.getName(city.buildingId), this.x + 5, this.y
						+ MARGIN_PANEL_HEIGHT);
			}
		} else
			GraphicsCustomFont.drawString(graphics, "None", this.x + 5, this.y + MARGIN_PANEL_HEIGHT);
		drawBox((byte) 6, Resource.PRODUCTION, 0, 10, city.getBuildingPP(), city.productionBox);
		GraphicsCustomFont.drawString(graphics, "Change ...", this.x + 5, this.y + 79);
		GraphicsCustomFont.drawString(graphics, "Buy", this.x + 5, this.y + 90);
		GraphicsCustomFont.drawString(graphics, "See Buildings ...", this.x + 5, this.y + 101);
		GraphicsCustomFont.drawString(graphics, "See Fortified Units ...", this.x + 5, this.y + 112);
		GraphicsCustomFont.drawString(graphics, "See Attached Units ...", this.x + 5, this.y + 123);
	}

	private void showInfosPanel() {
		drawResourcesInfos();
		drawBox((byte) 5, Resource.FOOD, 0, 60, city.getMaxFoodBox(), city.foodStorageBox);
	}

	private void showMapPanel() {
		drawMap();
		drawPopulation();
	}

	private void drawBox(final byte maxLines, final byte resourceType, final int dX, final int dY, final short max,
			final short quantity) {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		int nx = this.x + 5 + dX;
		int ny = this.y + MARGIN_PANEL_HEIGHT + dY;
		int boxWidth = 125;
		int countResourceX = 10;
		while (max / countResourceX > maxLines)
			countResourceX += 10;
		byte lines = (byte) (max / countResourceX);
		byte deltaX = (byte) Math.min(Resource.IMAGE_WIDTH, boxWidth / countResourceX);
		graphics.setColor(224, 224, 224);
		graphics.fillRect(nx - 1, ny - 1, ((countResourceX - 1) * deltaX) + 2 + Resource.IMAGE_WIDTH, lines
				* (Resource.IMAGE_HEIGHT + 1) + 2);
		for (short j = 0; j < lines && (j * countResourceX < quantity); j++) {
			for (short i = 0; i < countResourceX && (j * countResourceX + i < quantity); i++) {
				graphics.drawImage(ResourceFactory.getResource(resourceType).image, nx, ny, Graphics.TOP
						| Graphics.LEFT);
				nx += deltaX;
			}
			ny += Resource.IMAGE_HEIGHT + 1;
			nx = this.x + 5 + dX;
		}
	}

	private void drawResourcesInfos() {
		byte[] resources = { Resource.FOOD, Resource.PRODUCTION, Resource.TRADE, Resource.KNOWLEDGE, Resource.GOLD,
				Resource.LUXURY };
		byte[] resourcesCount = { city.getFood(), city.getProduction(), city.getTrade(), city.getTrade(),
				city.getKnowledge(player.knowledgeRate), city.getTax(player.taxRate), city.getLuxury(player.luxuryRate) };
		byte[] resourcesBonus = { city.getBonusFood(), city.getBonusProduction() };
		byte bonus;
		byte dY = 0;
		for (byte i = 0; i < resources.length; i++) {
			bonus = 0;
			if (i < resourcesBonus.length)
				bonus = resourcesBonus[i];
			if (i > 2)
				dY = Resource.IMAGE_HEIGHT;
			drawResourceInfos(resourcesCount[i], bonus, resources[i], i * (Resource.IMAGE_HEIGHT + 1) + dY);
		}
	}

	private void drawResourceInfos(final byte resourceCount, final byte resourceBonus, final byte resourceType,
			final int dY) {
		if (resourceCount == 0)
			return;
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		int boxWidth = 125;
		int nx = this.x + 5;
		int ny = this.y + MARGIN_PANEL_HEIGHT + dY;
		if (resourceBonus > 0)
			boxWidth -= Resource.IMAGE_WIDTH;
		byte delta = (byte) Math.min(Resource.IMAGE_WIDTH, boxWidth / resourceCount);
		for (short i = 0; i < resourceCount - resourceBonus; i++) {
			graphics.drawImage(ResourceFactory.getResource(resourceType).image, nx, ny, Graphics.TOP | Graphics.LEFT);
			nx += delta;
		}
		nx += Resource.IMAGE_WIDTH;
		for (short i = 0; i < resourceBonus; i++) {
			graphics.drawImage(ResourceFactory.getResource(resourceType).image, nx, ny, Graphics.TOP | Graphics.LEFT);
			nx += delta;
		}
	}

	private void drawMap() {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		Tile tile;
		Terrain terrain;
		int tileX;
		int tileY;
		mapCursor = new int[City.TILES_WIDTH][City.TILES_HEIGHT][2][2];
		for (short i = 0; i < 5; i++)
			for (short j = 0; j < 5; j++) {
				tile = city.getTile(i, j);
				if (tile != null) {
					if (tile.image != null) {
						terrain = tile.terrain;
						tileX = i * Tile.IMAGE_WIDTH + this.x + 10;
						tileY = j * Tile.IMAGE_HEIGHT + this.y + 20;
						graphics.drawImage(terrain.getImage(), tileX, tileY, Graphics.TOP | Graphics.LEFT);
						if (tile.city != null)
							graphics.drawImage(tile.city.image, tileX, tileY, Graphics.TOP | Graphics.LEFT);
						if (city.usedTiles[i][j])
							drawResources(tile, tileX, tileY, (short) (city.x + i - 2), (short) (city.y + j - 2));
						mapCursor[i][j][0][0] = tileX;
						mapCursor[i][j][0][1] = tileY;
						mapCursor[i][j][1][0] = Tile.IMAGE_WIDTH;
						mapCursor[i][j][1][1] = Tile.IMAGE_HEIGHT;
						graphics.setColor(128, 128, 128);
						graphics.drawRect(tileX, tileY, Tile.IMAGE_WIDTH, Tile.IMAGE_HEIGHT);
					}
				}
			}
	}

	private void drawResources(final Tile tile, final int tileX, final int tileY, final short mapX, final short mapY) {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		byte delta;
		Terrain terrain = tile.terrain;
		int resourceX = 0;
		int resourceY = 0;
		byte resourceType;
		byte resourceIndex;
		byte[] resources = { terrain.getFP(city.player), terrain.getPP(city.player),
				terrain.getTP(city.player, city, mapX, mapY) };
		delta = (byte) Math.floor(((Tile.IMAGE_WIDTH + 1 - Resource.IMAGE_WIDTH) * 2)
				/ (terrain.getFP(city.player) + terrain.getPP(city.player) + terrain.getTP(city.player, city, mapX,
						mapY)));
		for (resourceType = 0; resourceType < resources.length; resourceType++) {
			for (resourceIndex = 0; resourceIndex < resources[resourceType]; resourceIndex++) {
				graphics.drawImage(ResourceFactory.getResource(resourceType).image, tileX + 1 + (resourceX * delta),
						tileY + 1 + (resourceY * Resource.IMAGE_HEIGHT), Graphics.TOP | Graphics.LEFT);
				resourceX++;
				if (resourceX * delta > Tile.IMAGE_WIDTH - Resource.IMAGE_WIDTH) {
					resourceY++;
					resourceX = 0;
				}
			}
		}
	}

	private void drawPopulation() {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		graphics.setColor(192, 192, 192);
		graphics.fillRect(this.x + 2, this.y + 103, width - 3, People.IMAGE_HEIGHT * 2 + 3);
		short peopleIdx = 0;
		byte[] peopleDisplayOrder = { People.HAPPY, People.CONTENT, People.UNHAPPY, People.ARTIST, People.SCIENTIST,
				People.TAXMAN };
		int iDelta = People.IMAGE_WIDTH;
		if (People.IMAGE_WIDTH * city.getSize() > (width - 5) * 2)
			iDelta = (width - 5) * 2 / city.getSize();
		int currX = this.x + 3;
		int currY = this.y + 104;
		byte size = city.getSpecPeopleSize();
		popCursor = new int[size][2][2];
		availSpecPop = new byte[size];
		for (byte peopleType = 0; peopleType < peopleDisplayOrder.length; peopleType++) {
			size = city.getPeopleSize(peopleDisplayOrder[peopleType]);
			for (byte peopleIndex = 0; peopleIndex < size; peopleIndex++) {
				graphics.drawImage(
						PeopleFactory.getPeople(peopleDisplayOrder[peopleType], (byte) (peopleIndex % 2)).image, currX,
						currY, Graphics.TOP | Graphics.LEFT);
				if (peopleDisplayOrder[peopleType] == People.ARTIST
						|| peopleDisplayOrder[peopleType] == People.SCIENTIST
						|| peopleDisplayOrder[peopleType] == People.TAXMAN) {
					popCursor[peopleIdx][0][0] = currX - this.x - 1;
					popCursor[peopleIdx][0][1] = currY - this.y - 1;
					popCursor[peopleIdx][1][0] = People.IMAGE_WIDTH + 1;
					popCursor[peopleIdx][1][1] = People.IMAGE_HEIGHT + 1;
					availSpecPop[peopleIdx] = peopleDisplayOrder[peopleType];
					peopleIdx++;
				}
				if (currX < (this.x + width - People.IMAGE_WIDTH - 5))
					currX += iDelta;
				else {
					currX = this.x + 3;
					currY += People.IMAGE_HEIGHT + 1;
				}
			}
		}
	}

	private void showCityMapCursor() {
		MapCanvasEngine.canvas.graphics.setColor(255, 0, 0);
		MapCanvasEngine.canvas.graphics.drawRect(mapCursor[this.hCityMapIndex][this.vCityMapIndex][0][0],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][0][1],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][1][0],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][1][1]);
	}

	private void hideCityMapCursor() {
		MapCanvasEngine.canvas.graphics.setColor(128, 128, 128);
		MapCanvasEngine.canvas.graphics.drawRect(mapCursor[this.hCityMapIndex][this.vCityMapIndex][0][0],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][0][1],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][1][0],
				mapCursor[this.hCityMapIndex][this.vCityMapIndex][1][1]);
	}

	private void moveCityMapCursor(final byte dX, final byte dY) {
		hideCityMapCursor();
		do
			this.hCityMapIndex = (byte) ((this.hCityMapIndex + dX + 5) % 5);
		while ((mapCursor[this.hCityMapIndex][this.vCityMapIndex][0][0] == 0));
		if (vCityMapIndex + dY < 0 || vCityMapIndex + dY > 4
				|| (mapCursor[hCityMapIndex][vCityMapIndex + dY][0][0] == 0)) {
			moveVMapCursor(dY);
			return;
		}
		this.vCityMapIndex = (byte) (this.vCityMapIndex + dY);
		showCityMapCursor();
	}

	private void moveVMapCursor(final byte dY) {
		if (vMapIndex != 0 && city.getSpecPeopleSize() > 0)
			hideHPopCursor();
		else
			hideHCursor();
		this.vMapIndex = (byte) ((this.vMapIndex + dY + 3) % 3);
		if (vMapIndex == 1)
			showCityMapCursor();
		else if (vMapIndex == 2)
			if (city.getSpecPeopleSize() > 0)
				showHPopCursor();
			else
				moveVMapCursor(dY);
		else if (vMapIndex == 0)
			showHCursor();
	}

	private void showHPopCursor() {
		byte size = city.getSpecPeopleSize();
		if (size == 0) {
			moveVMapCursor((byte) -1);
			return;
		}
		if (this.hPopIndex >= size)
			this.hPopIndex = 0;
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		graphics.setColor(255, 0, 0);
		graphics.drawRect(this.x + popCursor[this.hPopIndex][0][0], this.y + popCursor[this.hPopIndex][0][1],
				popCursor[this.hPopIndex][1][0], popCursor[this.hPopIndex][1][1]);
	}

	private void hideHPopCursor() {
		Graphics graphics = MapCanvasEngine.canvas.graphics;
		graphics.setColor(192, 192, 192);
		graphics.drawRect(this.x + popCursor[this.hPopIndex][0][0], this.y + popCursor[this.hPopIndex][0][1],
				popCursor[this.hPopIndex][1][0], popCursor[this.hPopIndex][1][1]);
	}

	private void moveHPopCursor(final byte dX) {
		int size = city.getSpecPeopleSize();
		if (size > 0) {
			hideHPopCursor();
			this.hPopIndex = (byte) ((this.hPopIndex + dX + size) % size);
			drawPopulation();
			showHPopCursor();
		}
	}

	protected void showPanel() {
		super.showPanel();
		switch (this.hIndex) {
			case PROD_PANEL:
				showProductionPanel();
				break;
			case INFOS_PANEL:
				showInfosPanel();
				break;
			case MAP_PANEL:
				showMapPanel();
				break;
			default:
				break;
		}
		this.repaint();
	}

}
